package com.fastwire.carriere.discovery;

import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import com.fastwire.carriere.common.Messages;
import com.fastwire.carriere.common.constant.AppConstants;
import com.fastwire.carriere.common.exception.ResourceException;
import com.fastwire.carriere.common.exception.U2000ProcessException;
import com.fastwire.carriere.common.util.CommonLogger;
import com.fastwire.carriere.common.util.StringUtil;
import com.fastwire.carriere.dao.DAOException;
import com.fastwire.carriere.dao.DAOFactory;
import com.fastwire.carriere.dao.DiscoveryRecordDao;
import com.fastwire.carriere.discovery.entity.DiscoveryRecord;
import com.fastwire.carriere.inventory.entity.Equipment;
import com.fastwire.carriere.inventory.entity.NetworkElement;
import com.google.common.collect.Lists;

// TODO: Auto-generated Javadoc
/**
 * The Class HuaweiMTOSIDiscoveryInteraction.
 */
public class HuaweiMTOSIDiscoveryInteraction {

	private final DiscoveryRecordDao discoveryRecordDao = DAOFactory
			.getInstance().getDiscoveryRecordDao();

	/**
	 * Do ne ad hoc discovery.
	 * 
	 * @param neID
	 *            the ne id
	 * @throws DAOException
	 *             the dAO exception
	 * @throws ResourceException
	 */
	 // modified by Jun on 20120413
	public void doNEAdHocDiscovery(String neID) throws DAOException, ResourceException {		
		DiscoveryRecord discoveryRecord = precheckDiscovery(AppConstants.DISCOVERY_TYPE_ADHOC);

		NetworkEntityDiscovery neDiscovery = new NetworkEntityDiscovery();

		//List entityList = Lists.newArrayList();
		
		DAOFactory daoFactory = DAOFactory.getInstance();

		try {
			List<NetworkElement> allNes = Lists.newArrayList();

			if (!StringUtil.isEmptyString(neID)) {
				//NetworkElement ne = null;
				//ne= daoFactory.getNEDao().findNEbyName(neID);				
				NetworkElement ne = daoFactory.getNEDao().findNEbyName(neID);  // modified on 20120413

				if (ne == null) {
					List<NetworkElement> neList = neDiscovery.discoverAllNE();

					for (NetworkElement networkElement : neList) {

						if (neID.equals(networkElement.getEmsNativeName())) {
							ne = networkElement;
							break;
						}
					}
				}

				if (ne == null) {
					throw new ResourceException(Messages.getString(
							"message.discovery.adhoc.nenotexistent",
							new String[] { neID }));
				}
				allNes.add(ne);
			} else {
				allNes = neDiscovery.discoverAllNE();
			}

			// moved here on 20120416
			List entityList = Lists.newArrayList();
			for (NetworkElement ne : allNes) {
				Set<Equipment> eqList = neDiscovery.discoverAllEquipmentsbyNE(ne);
				ne.setEquipments(eqList);
				
				// modified on 20120413
				//entityList.addAll(neDiscovery.discoverAllTPsbyNE(neID)); 
				entityList.addAll(neDiscovery.discoverAllTPsbyNE(ne.getName()));
			}
			entityList.addAll(0, allNes);

			invalidateAllNEPhysicalResource(allNes);
			// modified by Jun on 20120413
			//daoFactory.getNEDao().saveOrUpdateAll(entityList);
			daoFactory.getNEDao().saveOrUpdateAdhoc(entityList);

			discoveryRecord.handleComplete();

		} catch (Exception e) {
			CommonLogger.error(this, e.getMessage());
			discoveryRecord.handleException(e.getMessage());

		} finally {
			discoveryRecordDao.saveOrUpdate(discoveryRecord);
		}

	}

	/**
	 * Invalidate all.
	 * 
	 * @param neList
	 *            the ne list
	 * @throws DAOException
	 *             the dAO exception
	 */

	/**
	 * Invalidate all service.
	 * 
	 * @param neList
	 *            the ne list
	 * @throws DAOException
	 *             the dAO exception
	 */
	//public
	private
	void invalidateAllService() throws DAOException {

		DAOFactory daoFactory = DAOFactory.getInstance();
		daoFactory.getFdfrDao().invalidateAll();
		daoFactory.getCrossConnectDao().invalidateAll();
		daoFactory.getProtectionGroupDao().invalidateAll();

	}

	public void invalidateAllNEPhysicalResource(List<NetworkElement> neList)
			throws DAOException {

		List objList = Lists.newArrayList();

		DAOFactory daoFactory = DAOFactory.getInstance();
		for (NetworkElement networkElement : neList) {
			NetworkElement ne = daoFactory.getNEDao().findNEbyName(networkElement.getName());  // ????

			if (ne != null) {
				objList.add(ne);
				objList.addAll(ne.getEquipments());
				objList.addAll(daoFactory.getTPDao().findTPbyNE(ne.getName()));
			}
		}

		daoFactory.getNEDao().invalidateAll(objList);

	}

	private synchronized DiscoveryRecord precheckDiscovery(String type)
			throws DAOException, ResourceException {

		List<DiscoveryRecord> wipDiscovery = discoveryRecordDao.findWIPDiscoverys();

		if (wipDiscovery != null && !wipDiscovery.isEmpty()) {
			throw new ResourceException(
					Messages.getString("message.discovery.discoverywip.exception"));
		}

		DiscoveryRecord discoveryRecord = new DiscoveryRecord(type);
		discoveryRecordDao.saveOrUpdate(discoveryRecord);
		return discoveryRecord;
	}

	public void doFullConcurrentDiscovery() throws U2000ProcessException,
			DAOException, ResourceException {

		DiscoveryRecord discoveryRecord = precheckDiscovery(AppConstants.DISCOVERY_TYPE_FULL);
		CommonLogger.info(this, "done precheck");
		try {

			NetworkEntityConcurrentDiscovery neDiscovery = new NetworkEntityConcurrentDiscovery();
			neDiscovery.doNEDiscovery(AppConstants.DISCOVERY_TYPE_FULL);

			List<Callable<List>> callables = neDiscovery.getCallables();

			if (!callables.isEmpty()) {

				ExecutorService executor = Executors
						.newFixedThreadPool(callables.size());
				List<Future<List>> futures = executor.invokeAll(callables);
				if (!executor.isShutdown()) {
					executor.shutdown();
				}
				while (!executor.isTerminated()) {
					executor.awaitTermination(1, TimeUnit.MINUTES);

				}
				List entityList = Lists.newArrayList();

				for (Future<List> future : futures) {
					entityList.addAll(future.get());
				}

				entityList.addAll(neDiscovery.discoverAllTopToplogicalLinks());
				entityList.addAll(neDiscovery.discoverAllTrafficConditioningProfile());

				CommonLogger.info(this, "Total entity:" + entityList.size());
				// above is the get data from U2000 
				
				// CEBS process
				DAOFactory.getInstance().getNEDao().saveOrUpdateAll(entityList);
			}
			discoveryRecord.handleComplete();

		} catch (Throwable e) {
			e.printStackTrace();
			CommonLogger.error(this, e.getMessage());
			discoveryRecord.handleException(e.getMessage());
		}

		finally {
			discoveryRecordDao.saveOrUpdate(discoveryRecord);
		}
	}

	public void doServiceDiscoveryConcurrent() throws DAOException,
			ResourceException {
		CommonLogger.info(this, "doServiceDiscoveryConcurrent");

		DAOFactory daoFactory = DAOFactory.getInstance();
		DiscoveryRecord discoveryRecord = precheckDiscovery(AppConstants.DISCOVERY_TYPE_SERVICE);

		NetworkEntityConcurrentDiscovery neDiscovery = new NetworkEntityConcurrentDiscovery();
		List entityList = Lists.newArrayList();

		try {
			List<NetworkElement> neList = daoFactory.getNEDao().findAllNEs();

			List<Callable<List>> callables = neDiscovery.getCallables(neList,
					AppConstants.DISCOVERY_TYPE_SERVICE);

			if (!callables.isEmpty()) {

				ExecutorService executor = Executors
						.newFixedThreadPool(callables.size());
				List<Future<List>> futures = executor.invokeAll(callables);
				if (!executor.isShutdown()) {
					executor.shutdown();
				}
				while (!executor.isTerminated()) {
					executor.awaitTermination(1, TimeUnit.MINUTES);

				}

				for (Future<List> future : futures) {
					entityList.addAll(future.get());
				}

				// modified on 20120412
				// invalidateAllService();
				daoFactory.getNEDao().saveOrUpdateAllService(entityList);
			}

			discoveryRecord.handleComplete();

		} catch (Exception e) {
			e.printStackTrace();
			CommonLogger.error(this, e.getMessage());
			discoveryRecord.handleException(e.getMessage());

		} finally {
			discoveryRecordDao.saveOrUpdate(discoveryRecord);
		}

		CommonLogger.info(this, "exiting doServiceDiscoveryConcurrent");

	}

}
